Skip to content

Implement wslc session enter#40088

Merged
OneBlue merged 16 commits intofeature/wsl-for-appsfrom
user/oneblue/session-enter
Apr 6, 2026
Merged

Implement wslc session enter#40088
OneBlue merged 16 commits intofeature/wsl-for-appsfrom
user/oneblue/session-enter

Conversation

@OneBlue
Copy link
Copy Markdown
Collaborator

@OneBlue OneBlue commented Apr 2, 2026

Summary of the Pull Request

This change creates a new wslc command: `wslc sesssion enter [--name ].

This command is design to be a long term replacement to wsl --wslc to be used for ephemeral debugging sessions (for instance when debugging the tests)

PR Checklist

  • Closes: Link to issue #xxx
  • Communication: I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected
  • Tests: Added/updated if needed and all pass
  • Localization: All end user facing strings can be localized
  • Dev docs: Added/updated if needed
  • Documentation updated: If checked, please file a pull request on our docs repo and link it here: #xxx

Detailed Description of the Pull Request / Additional comments

Validation Steps Performed

Copilot AI review requested due to automatic review settings April 2, 2026 21:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new wslc session enter command intended for ephemeral/debugging sessions by creating a session with a user-specified storage path, attaching an interactive shell, and adding test coverage around the new command.

Changes:

  • Introduces session enter as a new subcommand under session, including CLI argument definitions (storage-path, optional --name).
  • Implements the execution path for entering a session (task + service), launching an interactive shell attached to the current console.
  • Adds unit tests, command-line parsing test cases, and new E2E tests for session enter.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/windows/wslc/WSLCCLICommandUnitTests.cpp Adds unit tests validating SessionEnterCommand argument shape and non-empty descriptions.
test/windows/wslc/e2e/WSLCE2ESessionEnterTests.cpp Adds E2E coverage for interactive session enter flows (with/without name, deletion expectations, missing args).
test/windows/wslc/CommandLineTestCases.h Adds command-line parsing cases for session enter.
src/windows/wslc/tasks/SessionTasks.h Declares the new EnterSession task entrypoint.
src/windows/wslc/tasks/SessionTasks.cpp Implements EnterSession argument handling (storage path + optional name or generated GUID).
src/windows/wslc/services/SessionService.h Declares SessionService::Enter(...).
src/windows/wslc/services/SessionService.cpp Implements Enter(...) to create a session and launch/attach an interactive shell.
src/windows/wslc/services/SessionModel.h Adds non-const SessionOptions::Get() to allow modifying session settings.
src/windows/wslc/services/ConsoleService.h Adjusts AttachToCurrentConsole to be callable statically.
src/windows/wslc/commands/SessionEnterCommand.cpp Adds the new command implementation (enter) and wires it to EnterSession.
src/windows/wslc/commands/SessionCommand.h Declares SessionEnterCommand.
src/windows/wslc/commands/SessionCommand.cpp Registers SessionEnterCommand as a session subcommand.
src/windows/wslc/arguments/ArgumentDefinitions.h Adds the new positional argument type StoragePath (storage-path).

Comment on lines +125 to +129
options.Get()->DisplayName = displayName.c_str();
options.Get()->StoragePath = storagePath.c_str();

// Create a non-persistent session: lifetime is tied to our COM reference.
auto session = SessionService::CreateSession(options);
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SessionService::Enter currently calls SessionService::CreateSession(options), but CreateSession hard-codes WSLCSessionFlagsPersistent | WSLCSessionFlagsOpenExisting. That contradicts the “non-persistent” semantics described here and in SessionEnterCommand (and will cause the entered session to remain active/listed after the shell exits, or to unexpectedly reuse an existing session when the display name collides). Consider either adding a CreateSession overload that takes WSLCSessionFlags or creating the session directly in Enter() with WSLCSessionFlagsNone (and likely without OpenExisting) so the session is actually deleted when the COM reference is released.

Copilot uses AI. Check for mistakes.
Comment thread test/windows/wslc/e2e/WSLCE2ESessionEnterTests.cpp Outdated
@OneBlue OneBlue marked this pull request as ready for review April 3, 2026 01:23
@OneBlue OneBlue requested a review from a team as a code owner April 3, 2026 01:23
Copilot AI review requested due to automatic review settings April 3, 2026 01:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

m_storageVhdPath.c_str());

THROW_HR_WITH_USER_ERROR_IF(
HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND),
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the AttachDisk failure path, this always throws HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) when WSLCSessionStorageFlagsNoCreate is set, even if the actual failure was ERROR_FILE_NOT_FOUND (missing storage.vhdx in an existing directory). This can surface an incorrect HRESULT/error code to callers and make diagnostics harder. Consider throwing with the actual result HRESULT (and/or mapping both ERROR_PATH_NOT_FOUND and ERROR_FILE_NOT_FOUND appropriately) when NoCreate is set, rather than hard-coding ERROR_PATH_NOT_FOUND.

Suggested change
HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND),
result,

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +94
.Stderr = L"The system cannot find the path specified. \r\nError code: ERROR_PATH_NOT_FOUND\r\n",
.ExitCode = 1,
});
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test expects the system error string for a missing storage path, but the implementation throws a user-facing localized message (MessageWslcSessionStorageNotFound) when StorageFlags=NoCreate, so stderr will likely be the localized message + "Error code: ..." instead. Update the expected stderr (or adjust the implementation to intentionally use the system message) so the test matches the intended UX.

Suggested change
.Stderr = L"The system cannot find the path specified. \r\nError code: ERROR_PATH_NOT_FOUND\r\n",
.ExitCode = 1,
});
.ExitCode = 1,
});
VERIFY_IS_TRUE(result.Stderr.has_value());
VERIFY_IS_TRUE(result.Stderr->find(L"Error code: ERROR_PATH_NOT_FOUND\r\n") != std::wstring::npos);

Copilot uses AI. Check for mistakes.
Comment on lines 426 to 439
@@ -427,6 +435,7 @@ typedef struct _WSLCSessionSettings {
[unique] ITerminationCallback* TerminationCallback;
WSLCFeatureFlags FeatureFlags;
WSLCHandle DmesgOutput;
WSLCSessionStorageFlags StorageFlags;

Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding StorageFlags to WSLCSessionSettings and WSLCSessionInitSettings changes the wire/layout contract used by IWSLCSessionManager::CreateSession. This is an ABI/RPC breaking change for any external SDK consumers built against the previous struct definition. To keep compatibility, this should be versioned (e.g., introduce a WSLCSessionSettingsV2/InitSettingsV2 with a new CreateSessionV2 entry point or a size/version field pattern) rather than modifying the existing structs in-place.

Copilot uses AI. Check for mistakes.
THROW_HR_IF_MSG(
E_INVALIDARG,
WI_IsAnyFlagSet(Settings->StorageFlags, ~WSLCSessionStorageFlagsValid),
"Invalid storage flags flags: %i",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: duplicate "flags" in error message

Copy link
Copy Markdown
Member

@dkbennett dkbennett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like an exemplary CLI command implementation! Few comments that are not blocking.

COMMAND_LINE_TEST_CASE(L"session terminate session1", L"terminate", true)
COMMAND_LINE_TEST_CASE(L"session terminate", L"terminate", true)
COMMAND_LINE_TEST_CASE(L"session enter C:\\storage", L"enter", true)
COMMAND_LINE_TEST_CASE(L"session enter C:\\storage --name my-session", L"enter", true)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"session enter --name foo c:\storage" should also be valid, but not necessary, we have lots of coverage of this pattern for commands.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to push another iteration to fix something else, will add

{
WSL2_TEST_ONLY();

auto session = RunWslcInteractive(std::format(L"session enter \"{}\"", SessionOptions::GetStoragePath()));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this pattern of using the default storage location for session enter a common way of doing it, or just for convenient testing? If it's common then perhaps we can make the storage path not required and use GetStoragePath internally if no path is provided to use the default session's storage.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just used that to make testing convenient (and faster), since we're in the CLI tests we need that the CLI session exists.

Right now I don't think we'd want wslc session enter to use the CLI session storage by default, because that would create a non persistent session that will use the CLI's storage but a different name, which would lead to confusing errors if the users tried to use the CLI session in the "regular" way in parallel

Copilot AI review requested due to automatic review settings April 3, 2026 18:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.

Comment on lines 436 to 440
[unique] ITerminationCallback* TerminationCallback;
WSLCFeatureFlags FeatureFlags;
WSLCHandle DmesgOutput;
WSLCSessionStorageFlags StorageFlags;

Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WSLCSessionSettings is part of the COM/RPC contract for IWSLCSessionManager::CreateSession. Adding StorageFlags changes the struct layout and will break existing clients built against the previous header/IDL. This should be versioned (e.g., introduce a WSLCSessionSettingsV2 + CreateSession2, or another backward-compatible mechanism) rather than modifying the existing struct in-place.

Copilot uses AI. Check for mistakes.
Comment on lines 564 to 568
ULONG CreatorPid;
LPCWSTR DisplayName;
LPCWSTR StoragePath;
WSLCSessionStorageFlags StorageFlags;
ULONGLONG MaximumStorageSizeMb;
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WSLCSessionInitSettings is also part of the cross-process initialization contract. Adding StorageFlags changes the marshaled struct layout and breaks compatibility with older components (service/user COM server) that still expect the previous struct definition. Consider versioning the init settings struct (or the Initialize call) instead of extending it in-place.

Copilot uses AI. Check for mistakes.
Comment thread src/windows/service/inc/wslc.idl Outdated
WSLCSessionFlagsNone = 0,
WSLCSessionFlagsPersistent = 1, // Session remains active after its COM reference is released.
WSLCSessionFlagsOpenExisting = 2, // Open an existing session if the name is in use.
WSLCSessionFlagsOpenExistingStorage = 4, // Only open an existing storage folder, don't create one if it doesn't already exist.
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WSLCSessionFlagsOpenExistingStorage is introduced in the IDL, but there is no implementation that checks this bit (only WSLCSessionFlagsOpenExisting/Persistent are used in WSLCSessionManager). Either implement its semantics in the service or remove it to avoid a misleading/unused public flag.

Suggested change
WSLCSessionFlagsOpenExistingStorage = 4, // Only open an existing storage folder, don't create one if it doesn't already exist.

Copilot uses AI. Check for mistakes.
Comment thread src/windows/common/WslClient.cpp
Comment on lines +36 to +37
// Terminate the wslc session since we use its storage path in this test class.
RunWslc(L"session terminate");
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TestClassSetup calls RunWslc(L"session terminate") without asserting success or explicitly tolerating expected failures (e.g., session not present). Consider using the existing EnsureSessionIsTerminated() helper (or at least verifying the result / tolerating ERROR_NOT_FOUND) so setup failures don’t silently mask issues or leave state behind.

Suggested change
// Terminate the wslc session since we use its storage path in this test class.
RunWslc(L"session terminate");
// Terminate any existing wslc session since we use its storage path in this test class.
EnsureSessionIsTerminated();

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's because that session isn't necessarily running

#include "precomp.h"
#include "SessionService.h"
#include "ConsoleService.h"
#include "UserSettings.h"
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UserSettings.h appears unused in this translation unit (no symbols referenced from it). Consider dropping the include to reduce build dependencies and avoid unused-include drift.

Suggested change
#include "UserSettings.h"

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 4, 2026 02:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (2)

src/windows/service/inc/wslc.idl:444

  • Adding StorageFlags to WSLCSessionSettings (and the related init/settings structs) changes the COM/RPC contract shape generated from this IDL. If there are any external clients (SDK/nuget) built against the previous IDL, this is a breaking change and typically requires versioning (new struct/interface/IID) rather than in-place modification.
typedef enum _WSLCSessionStorageFlags
{
    WSLCSessionStorageFlagsNone = 0,
    WSLCSessionStorageFlagsNoCreate = 1, // Open an existing storage path, but don't create a new one.
    WSLCSessionStorageFlagsValid = WSLCSessionStorageFlagsNoCreate
} WSLCSessionStorageFlags;

cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSessionStorageFlags);")

// Settings for IWSLCSessionManager::CreateSession - full session configuration
typedef struct _WSLCSessionSettings {
    LPCWSTR DisplayName;
    LPCWSTR StoragePath;
    ULONGLONG MaximumStorageSizeMb;
    ULONG CpuCount;
    ULONG MemoryMb;
    ULONG BootTimeoutMs;
    WSLCNetworkingMode NetworkingMode;
    [unique] ITerminationCallback* TerminationCallback;
    WSLCFeatureFlags FeatureFlags;
    WSLCHandle DmesgOutput;
    WSLCSessionStorageFlags StorageFlags;

    // Below options are used for debugging purposes only.
    [unique] LPCWSTR RootVhdOverride;
    [unique] LPCSTR RootVhdTypeOverride;
} WSLCSessionSettings;

src/windows/common/WslClient.cpp:1766

  • wsl.exe --wslc support is removed here (the argument is no longer handled). Since the PR description frames wslc session enter as a long-term replacement, consider either keeping --wslc as a deprecated alias that forwards to the new command (or printing a clear upgrade message) to avoid a silent breaking change for existing workflows.
        else if (argument == WSL_UNINSTALL_ARG)
        {
            commandLine = wsl::windows::common::helpers::ConsumeArgument(commandLine, argument);
            argument = wsl::windows::common::helpers::ParseArgument(commandLine);
            if (!argument.empty())
            {
                wsl::windows::common::wslutil::PrintMessage(
                    Localization::MessageUninstallNoArguments(WSL_UNINSTALL_ARG, WSL_UNREGISTER_ARG), stdout);
                return exitCode;
            }

            return Uninstall();
        }
        else
        {
            if ((argument.size() > 0) && (argument[0] == L'-'))
            {

<data name="WSLCCLI_ImageLoadNoInputError" xml:space="preserve">
<value>Requested load but no input provided.</value>
</data>
>>>>>>> origin/feature/wsl-for-apps
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a leftover merge-conflict marker (">>>>>>> origin/feature/wsl-for-apps") in this .resw file, which will break localization parsing/build. Remove the conflict marker and ensure the XML is well-formed before merging.

Suggested change
>>>>>>> origin/feature/wsl-for-apps

Copilot uses AI. Check for mistakes.
Comment on lines 688 to +697
typedef enum _WSLCSessionFlags
{
WSLCSessionFlagsNone = 0,
WSLCSessionFlagsPersistent = 1, // Session remains active after its COM reference is released.
WSLCSessionFlagsOpenExisting = 2, // Open an existing session if the name is in use.
WSLCSessionFlagsOpenExistingStorage = 4, // Only open an existing storage folder, don't create one if it doesn't already exist.
} WSLCSessionFlags;

cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSessionFlags);")

Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WSLCSessionFlagsOpenExistingStorage is added to the public flags enum, but WSLCSessionManagerImpl::CreateSession currently only consults WSLCSessionFlagsOpenExisting and WSLCSessionFlagsPersistent when deciding behavior. As-is, this new flag appears to have no effect; either plumb it through (e.g., map it to StorageFlagsNoCreate) or remove it to avoid misleading API surface.

Copilot uses AI. Check for mistakes.
/*_(Scheme, "scheme", NO_ALIAS, Kind::Value, Localization::WSLCCLI_SchemeArgDescription())*/ \
_(Session, "session", NO_ALIAS, Kind::Value, Localization::WSLCCLI_SessionIdArgDescription()) \
_(SessionId, "session-id", NO_ALIAS, Kind::Positional, Localization::WSLCCLI_SessionIdPositionalArgDescription()) \
_(StoragePath, "storage-path", NO_ALIAS, Kind::Positional, L"Path to the session storage directory") \
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ArgType::StoragePath is introduced with a hard-coded English description string. All other arguments in this table use Localization::WSLCCLI_* resources, and this PR also adds WSLCCLI_SessionStoragePositionalArgDescription in Resources.resw but it isn't used here. Please wire this argument description to a localized resource for consistency and localization support.

Suggested change
_(StoragePath, "storage-path", NO_ALIAS, Kind::Positional, L"Path to the session storage directory") \
_(StoragePath, "storage-path", NO_ALIAS, Kind::Positional, Localization::WSLCCLI_SessionStoragePositionalArgDescription()) \

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +43
ArgType::Name, std::nullopt, std::nullopt, L"Name for the session. If not provided, a GUID is generated."),
};
}

std::wstring SessionEnterCommand::ShortDescription() const
{
return {L"Enter a temporary session."};
}

std::wstring SessionEnterCommand::LongDescription() const
{
return {
L"Creates a non-persistent session with the given storage path and opens a shell into it. "
L"The session is deleted when the shell exits. If no name is provided, a GUID is generated and printed to stderr."};
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This command introduces multiple user-facing help/description strings as raw literals (Name for the session..., Enter a temporary session., and the long description). Other commands use Localization::WSLCCLI_* resources for these strings; please add corresponding localized resources and use them here so wslc --help output can be localized consistently.

Suggested change
ArgType::Name, std::nullopt, std::nullopt, L"Name for the session. If not provided, a GUID is generated."),
};
}
std::wstring SessionEnterCommand::ShortDescription() const
{
return {L"Enter a temporary session."};
}
std::wstring SessionEnterCommand::LongDescription() const
{
return {
L"Creates a non-persistent session with the given storage path and opens a shell into it. "
L"The session is deleted when the shell exits. If no name is provided, a GUID is generated and printed to stderr."};
ArgType::Name, std::nullopt, std::nullopt, Localization::WSLCCLI_SESSIONENTER_NAME_DESCRIPTION),
};
}
std::wstring SessionEnterCommand::ShortDescription() const
{
return {Localization::WSLCCLI_SESSIONENTER_DESCRIPTION};
}
std::wstring SessionEnterCommand::LongDescription() const
{
return {Localization::WSLCCLI_SESSIONENTER_LONG_DESCRIPTION};

Copilot uses AI. Check for mistakes.
Comment thread src/windows/wslc/services/SessionService.cpp Outdated
Comment on lines +129 to +132
// TODO: Consider adding a 'create' verb to do that.
auto session = SessionService::CreateSession(options, WSLCSessionFlagsOpenExistingStorage);
wsl::windows::common::wslutil::PrintMessage(std::format(L"Created session: {}", displayName), stderr);

Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The status output Created session: ... is user-facing and currently hard-coded via std::format. Please route this through the localization system (e.g., a Localization::... resource) so the interactive command output can be localized consistently with the rest of the CLI.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 4, 2026 02:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.

Comment on lines 435 to 440
WSLCNetworkingMode NetworkingMode;
[unique] ITerminationCallback* TerminationCallback;
WSLCFeatureFlags FeatureFlags;
WSLCHandle DmesgOutput;
WSLCSessionStorageFlags StorageFlags;

Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding StorageFlags to WSLCSessionSettings changes the MIDL struct layout used by IWSLCSessionManager::CreateSession. This is an ABI/RPC contract break for any existing clients (including external SDK consumers) built against the previous struct definition, and can lead to proxy/stub mismatch or the service reading past the caller’s buffer. Please version this contract (e.g., introduce a new WSLCSessionSettings2 + CreateSession2 on a new IWSLCSessionManager IID) or use an explicit size/version field so older clients remain compatible.

Copilot uses AI. Check for mistakes.
auto session = SessionService::CreateSession(options, WSLCSessionFlagsNone);
wsl::windows::common::wslutil::PrintMessage(Localization::MessageWslcCreatedSession(displayName), stderr);

const std::string shell = "/bin/sh";
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/bin/sh is being launched with --login, which is not a portable/standard option for sh (it’s typically a bash-ism). On many distros /bin/sh is dash/busybox and this will fail immediately, breaking wslc session enter. Consider switching to /bin/bash --login (as the previous debug shell did) or dropping the --login argument when using /bin/sh.

Suggested change
const std::string shell = "/bin/sh";
const std::string shell = "/bin/bash";

Copilot uses AI. Check for mistakes.
Comment on lines +377 to +378
HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND),
Localization::MessageWslcSessionStorageNotFound(Settings.StoragePath),
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When AttachDisk fails with ERROR_FILE_NOT_FOUND (missing storage.vhdx in an existing directory), this path still throws ERROR_PATH_NOT_FOUND if WSLCSessionStorageFlagsNoCreate is set. That changes the error code and can produce misleading diagnostics. Consider preserving the actual result (ERROR_FILE_NOT_FOUND vs ERROR_PATH_NOT_FOUND) when NoCreate is set, and tailor the user message accordingly.

Suggested change
HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND),
Localization::MessageWslcSessionStorageNotFound(Settings.StoragePath),
result,
Localization::MessageWslcSessionStorageNotFound(
result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ? m_storageVhdPath.c_str() : Settings.StoragePath),

Copilot uses AI. Check for mistakes.
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name = "MessageWslcSessionStorageNotFound" xml:space = "preserve" >
<value>No WSLC session found in '{}'</value>
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MessageWslcSessionStorageNotFound currently says "No WSLC session found in '{}'", but it’s used when the storage path doesn’t exist / can’t be opened. This reads like a lookup failure by name rather than a filesystem/storage issue. Consider rewording to reference the storage path (e.g., "No WSLC session storage found at '{}'" or similar) to make the error actionable.

Suggested change
<value>No WSLC session found in '{}'</value>
<value>No WSLC session storage found at '{}'</value>

Copilot uses AI. Check for mistakes.
@OneBlue OneBlue merged commit 9d39805 into feature/wsl-for-apps Apr 6, 2026
11 checks passed
kvega005 added a commit that referenced this pull request May 7, 2026
…ronization (#40300)

* Fix X Y (#14514)

* Rethink image parsing logic (#14496)

* Save state

* Rethink image parsing to correctly handle different reference formats

* Foramt

* Fix merge

* Apply PR feedback

* Format

* Apply PR feedback

* Use a regex based parser

* Format

* Reset the test session after termination

* Fix test case

* Apply PR feedback

* Set container cursor (#14516)

* Container cursor

* Update pull image callback

* Clang format

* Signal wslcsdk.dll in the release pipeline (#14517)

* Add volume alias  (#14518)

* Add volume alias

* Fix Tests

* Add DCAT registration remediation (#14450)

* Rename image delete to remove and add aliases (#14521)

* Rename image delete to remove

* Clang format

* Handle singular/plural units in FormatRelativeTime

* Add more WSLC E2E tests (#14365)

* Initial support for WSLC E2E tests

* More E2E tests

* More E2E tests

* WIP

* CP exit code fix

* Enhance structure

* Added E2E file

* Clang format

* Added E2E test

* Enhance structure

* Clang format

* Update header comment

* Update wslc path

* Resolving copilot comments

* Added E2E test

* Pull latest

* Addressed comments

* Addressed comments

* Clang format

* Addressed comments

* Load image

* Addressed comments

* Pull latest

* Addressed comments

* E2E test for wslc container delete

* Addressed comments

* Resolving copilot comments

* Added E2E test

* Added E2E test

* Added E2E test

* Added E2E test

* Added E2E test

* Added E2E test

* Added E2E test

* Added E2E test

* Added E2E test

* Fix test

* Added E2E tests

* Added E2E tests

* Added E2E tests

* Added E2E tests

* Added E2E tests

* Added E2E tests

* Added E2E tests

* Resolve copilot comment

* Clang format

* Replace S_OK with 0

* Resolve copilot comment

* Addressed comments

* Resolve copilot comment

* Update test after latest changes

* Implement SDK IO callbacks (#14462)

Implements `WslcSetProcessSettingsIOCallback` and the use of those inputs for both initial and subsequent processes.  A new thread is started to run the `MultiHandleWait` and the container/process objects hold a `shared_ptr` reference to it.  The caller must keep one of the objects alive for the callback thread to keep working.

* test: add support for ARM64 WSLC testing. (#14519)

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Localization change from build: 142911151 (#14535)

Co-authored-by: WSL localization <noreply@microsoft.com>

* Initialize environment and add E2E tests with formatting (#14475)

* Init env

* Added E2E tests

* Clang format

* WIP

* Init tests

* Added UT

* Added more UT

* Added more E2E Tests

* Added more E2E Tests

* Code enhancement

* Added more E2E Tests

* Added more E2E Tests

* Added more E2E Tests

* Clang format

* Resolve copilot comment

* Addressed comments

* Fix test

* Addressed comments

* merge master -> feature/wsl-for-apps (#14537)

* test: enable virtiofs tests and enable WSLG during testing (#14387)

* test: enable virtiofs tests and enable WSLG during testing

* test fix

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* chore(distributions): Almalinux auto-update - 20260311 14:52:02 (#14404)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Fix CVE-2026-26127: bump .NET runtime from 10.0.0 to 10.0.4 (#14421)

Addresses Dependabot alerts #10 and #11. The Microsoft.NETCore.App.Runtime
packages (win-x64 and win-arm64) at version 10.0.0 are vulnerable to a
denial of service via out-of-bounds read when decoding malformed Base64Url
input (CVSS 7.5 High). Bumped to 10.0.4 which includes the fix.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Notice change from build: 141806547 (#14423)

Co-authored-by: WSL notice <noreply@microsoft.com>

* Ship initrd.img in MSI using build-time generation via powershell script (#14424)

* Ship initrd.img in MSI using build-time generation via tar.exe

Replace the install-time CreateInitrd/RemoveInitrd custom actions with a
build-time step that generates initrd.img using the Windows built-in
tar.exe (libarchive/bsdtar) and ships it directly in the MSI.

The install-time approach had a race condition: wsl.exe could launch
before the CreateInitrd custom action completed, causing
ERROR_FILE_NOT_FOUND for initrd.img.

Changes:
- Add CMake custom command to generate initrd.img via tar.exe --format=newc
- Add initrd.img as a regular file in the MSI tools component
- Remove CreateInitrd/RemoveInitrd custom actions from WiX, DllMain,
  and wslinstall.def
- Remove CreateCpioInitrd helper and its tests (no longer needed)
- Update pipeline build targets to build initramfs instead of init

* pr feedback

* more pr feedback

* switch to using a powershell script instead of tar.exe

* powershell script feedback

* hopefully final pr feedback

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* virtiofs: update logic so querying virtiofs mount source does not require a call to the service (#14380)

* virtiofs: update logic so querying virtiofs mount source does not require a call to the service

* more pr feedback

* use std::filesystem::read_symlink

* pr feedback and use canonical path in virtiofs symlink

* make sure canonical path is always used

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* virtio networking: add support for ipv6 (#14350)

* VirtioProxy: Add IPv6 address, gateway, and route support

- Add PreferredIpv6Address field and GetBestGatewayV6* methods to NetworkSettings
- Extend GetHostEndpointSettings() to discover IPv6 unicast address and gateway
- Add UpdateIpv6Address() using ModifyGuestEndpointSettingRequest<IPAddress>
- Push IPv6 default route to guest via UpdateDefaultRoute(AF_INET6)
- Remove AF_INET6 early return in ModifyOpenPorts, use INETADDR_PORT()
- Add EndpointRoute::DefaultRoute() static factory
- Pass client_ip_ipv6 in devicehost options (not yet parsed by devicehost)
- Remove gateway_ip from devicehost options (only needed for DHCP)
- Include IPv6 DNS servers in non-tunneling DNS settings
- Add ConfigurationV6 and DnsResolutionAAAA tests

* cleanup and add more ipv6 tests

* added test coverage and minor updates

* clang format

* pr feedback

* format source

* pr feedback

* test fixes

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Track `bind` syscall when port is 0 (#14333)

* Initial work

* .

* pr feedback and add unit test

* minor tweaks an fix use after free in logging statement

* implement PR feedback

* hopefully final pr feedback

* pr feedback in test function

* Address PR feedback: add try/catch to TrackPort and PortZeroBind queue push

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Add iptables to list of apps to install in WSL (#14459)

There were instructions already on how to install tcpdump in WSL, but
iptables are also needed for the log collection to be complete, so this
PR adds instructions on how to also install iptables.

Co-authored-by: Andre Muezerie <andremue@linux.microsoft.com>

* Update Microsoft.WSL.DeviceHost to version 1.1.39-0 (#14460)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Moves all Ubuntu distros to the tar-based format (#14463)

* Move all supported Ubuntu images to the new format

We backported the build pipeline so all current LTSes come out in the new tar-based format

* Remove the appx based distros

All WSL users can run tar-based distros by now, right?
There is no benefit in maintaining both formats.

* Enable DNS tunneling for VirtioProxy networking mode (#14461)

- Allow VirtioProxy to keep EnableDnsTunneling=true in config, but clear
  socket-specific options (BestEffortDnsParsing, DnsTunnelingIpAddress)
- Suppress dedicated DNS tunneling hvsocket for VirtioProxy; tunneling
  is handled through the VirtioNetworking device host instead
- Set DnsTunneling flag on VirtioNetworkingFlags so the device host
  knows to tunnel DNS
- Expand SWIOTLB kernel cmdline to cover VirtioFs and VirtioProxy
- Bump DeviceHost package to 1.1.39-0
- Add VirtioProxy DNS test coverage for tunneling on/off
- Skip GuestPortIsReleasedV6 on Windows 10

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* test: disable LoopbackExplicit due to OS build 29555 regression (#14477)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Refactor: trim unnecessary DLL deps from COMMON_LINK_LIBRARIES (#14426)

* Refactor: trim unnecessary DLL deps from COMMON_LINK_LIBRARIES

- Split MSI/Wintrust install functions from wslutil.cpp into install.cpp
- Remove MI.lib, wsldeps.lib, msi.lib, Wintrust.lib, computecore.lib,
  computenetwork.lib, Iphlpapi.lib from COMMON_LINK_LIBRARIES
- Add per-target MSI_LINK_LIBRARIES, HCS_LINK_LIBRARIES, SERVICE_LINK_LIBRARIES
- Delay-load msi.dll and WINTRUST.dll for wsl.exe and wslg.exe
- Result: wslhost, wslrelay, wslcsdk, testplugin lose msi/wintrust startup imports;
  wsl.exe and wslg.exe defer msi/wintrust loading until actually needed;
  wslservice is the only target that imports computecore/computenetwork/Iphlpapi

* minor fixes to install.cpp that were caught during PR

* move to wsl::windows::common::install namespace

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Fix wsl stuck when misconfigured cifs mount presents (#14466)

* detach terminal before running mount -a

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* use _exit on error before execv in child process to avoid unintentional resource release

* Add regression test

* Fix clang format issue

* fix all clang format issue

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* resolve ai comments

* move test to unit test

* Fix string literal

* Overwrite fstab to resolve pipeline missing file issue

---------

Co-authored-by: Feng Wang <wangfen@microsoft.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Update localization and notice scripts to target the branch that the pipeline is running on (#14492)

* test: Add arm64 test distro support (#14500)

* test: Add arm64 test distro support

* update unit test baseline

* more test baseline updates

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* test: remove duplicated DNS test coverage (#14522)

* test: remove duplicated DNS test coverage

* format source

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Fix: Fail and warn the user when --uninstall is given parameters (#14524)

Fail and warn the user when --uninstall is given parameters.

* Localization change from build: 142847827 (#14525)

Co-authored-by: WSL localization <noreply@microsoft.com>

* virito net: revert to previous DNS behavior while we debug an issue with DNS over TCP (#14532)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* devicehost: update to latest devicehost nuget with tracing improvements (#14531)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* fix merge issues

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: AlmaLinux Autobot <107999298+almalinuxautobot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Blue <OneBlue@users.noreply.github.com>
Co-authored-by: WSL notice <noreply@microsoft.com>
Co-authored-by: Daman Mulye <daman_mulye@hotmail.com>
Co-authored-by: Andre Muezerie <108841174+andremueiot@users.noreply.github.com>
Co-authored-by: Andre Muezerie <andremue@linux.microsoft.com>
Co-authored-by: Carlos Nihelton <carlos.santanadeoliveira@canonical.com>
Co-authored-by: Feng Wang <wang6922@outlook.com>
Co-authored-by: Feng Wang <wangfen@microsoft.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* cleanup: rename wsla -> wslc (#14502)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* [CLI] Added support for entrypoint (#14552)

* Added entrypoint

* Enhance tests

* Initial wslc settings support (#14548)

* Various improvements to interactions with user-provided handles (#14486)

* Save state

* Add test coverage

* Check the event under the lock

* Apply PR feedback

* Format

* Apply PR feedback

* Various improvements to PullImage()  + custom registry support (#14549)

* Save state

* Save state

* Handle issues during pull

* Disable the pull tests

* Update the CLI tests

* Format

* Fix legacy index logic

* Add test coverage for failed PullImage()

* Update test/windows/WSLCTests.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Use pre-imported container images in the tests to avoid hitting the API limit (#14561)

* Use pre-imported container images in the tests to avoid hitting the API limit

* Fix test case

* Update test/windows/wslc/e2e/WSLCE2EImageBuildTests.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Correctly set FileOffsets in WriteHandle (#14562)

* Correctly set FileOffsets in WriteHandle

* Apply PR suggestions

* Update Microsoft.WSL.DeviceHost to version 1.1.48-0 (#14575)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Allow retrieving state and init process info after container auto remove (#14429)

Allow clients to continue reading stdout/stderr and querying state from containers after they've been deleted, by caching the read-only data in the com wrapper.

* Fix StateChangedAt mismatch during container recovery from storage (#14482)

* Use Docker's FinishedAt timestamp in Transition() to fix StateChangedAt mismatch during container recovery

* Extract GetDockerFinishedAt() helper

* Address Feedback

* Fail if Docker event time is missing

* Address copilot feedback

* Use Docker stop event timestamp instead of InspectContainer()

* Apply copilot feedback

* PR Feedback

* [WSLC] add WSLC CMake file in NuGet (#14543)

Add WSLC SDK Config.cmake file. Enable developers to consume the library with CMake.

* win10: remove IsWslSupportInterfacePresent check from wslservice (#14546)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Fix localization and notice pipelines to use full branch name (#14566)

Build.SourceBranchName only returns the last segment after '/', breaking
branches with slashes (e.g. user/benhill/loc_fix -> loc_fix). Use
Build.SourceBranch with refs/heads/ stripped instead.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Remove the CTests targets from yaml-cpp (#14563)

* Fix wrong enum type in DeleteExclusiveLockHeld (#40030)

WSLCDeleteImageFlagsForce (from WSLCDeleteImageFlags enum) was used instead
of WSLCDeleteFlagsForce (from WSLCDeleteFlags enum). Both values are currently
1, so no functional issue today, but this is a type confusion that will break
silently if either enum changes.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Fix Content-Length truncation for Docker responses >4GB (#40033)

std::stoul returns unsigned long (32-bit on Windows), truncating Content-Length
values >4GB. This corrupts the socket stream for large image save/export
operations.

Replace with std::stoull to parse as 64-bit unsigned.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* wslc: resolve ContainerRecoveryFromStorage test issue by storing timestamp from docker, not the host (#40038)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Reject port mappings exceeding 63-port limit in relay (#40035)

WaitForMultipleObjects has a 64-handle limit. The accept thread uses
1 handle for the exit event, leaving room for 63 port mappings.

Reject new port mappings with ERROR_TOO_MANY_OPEN_FILES when the limit
is reached, rather than crashing the relay thread. Existing mappings
continue to work.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Add networking mode setting as fallback (#14564)

* Fix partial write data loss in TTY stdin relay (#40032)

When the TtyMaster fd is non-blocking, write() can return fewer bytes than
requested (partial write). The existing code only handled the EAGAIN/EWOULDBLOCK
case by buffering into pendingStdin, but silently dropped data on successful
partial writes.

Add handling for 0 < bytesWritten < bytesRead to buffer the unwritten bytes
into pendingStdin, matching the existing retry logic.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Fix deadlock between WatchForExitedProcesses and VMProcessControl destructor (#14567)

Use weak_ptr in m_trackedProcesses so WatchForExitedProcesses can safely
lock a reference and call OnExited() outside m_trackedProcessesLock.

weak_ptr avoids a circular reference: the vector no longer prevents
VMProcessControl destruction, so the destructor's OnProcessReleased
cleanup runs normally. Expired entries are also pruned in OnProcessReleased.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Clean up Docker container on Create() failure (#40034)

* Clean up Docker container on Create() failure

If InspectContainer or the WSLCContainerImpl constructor throws after
CreateContainer succeeds, the Docker container is permanently orphaned
with no way to manage it through WSLC APIs.

Add a scope_exit to delete the Docker container on failure, released
on success.

* pr feedback (capture by value)

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* CLI: Implement --session argument and session targeting (#14368)

* Remove options that are not yet implemented (#40044)

* Add cancellation to image build (#14453)

* wslc: enable virtiofs by default for wslc.exe and wslcsdk (#14559)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* wslc: fix TOCTOU race in cached COM wrapper getters (#40039)

GetState/GetInitProcess/GetId/GetName could race with DisconnectComWrapper:
the cache check saw empty, then disconnect populated the cache and nulled
the impl, so the forwarded call failed with RPC_E_DISCONNECTED even though
the cached value was now available.

Fix by removing the upfront cache check and instead calling through to the
impl first. If the call fails with RPC_E_DISCONNECTED, fall back to the
cache which DisconnectComWrapper guarantees is populated.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Validate empty host path in VolumeMount::Parse (#40031)

* Validate empty host path in VolumeMount::Parse

When parsing volume mount specs without a mode suffix (e.g. ':container'),
the host path validation was skipped, producing a VolumeMount with an empty
host path. This would propagate to MountWindowsFolder('') and produce a
confusing error.

Add validation after computing m_hostPath to reject empty host paths with
a clear error message in all cases.

* add test coverage

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Update wslc build to look for Containerfile and Dockerfile (#40045)

* Save state

* Add test coverage

* Rename method

* Require input handle in the service

* Apply PR feedback

* Format

* Apply PR feedback + update tests

* Format

* Implement WSLAContainer::Kill() (#14560)

* Implement WSLAContainer::Kill()

* Add test coverage

* Format

* Apply PR feedback

* Fix a race in `container start -a` for short-lived containers. (#14558)

* Localization change from build: 143374899 (#40049)

Co-authored-by: WSL localization <noreply@microsoft.com>

* [CLI] Add initial support for image saving feature (#14557)

* Initial support for image save

* Added e2e tests

* Added session option

* Clang format

* Clang format

* Addressed comments

* CLang format

* Change RegistryAuthenticationInformation to optional string (#40053)

* Implement SDK CanRun (#14539)

Implements `WslcCanRun` using existing primitives.  Updates the component flag names to help better describe their meaning and adds comments to further do so.

Also changes the error returned when we cannot create a `WSLASessionManager` and WSL is installed at a version below the minimum for WSLC support.

* CLI: Create elevated and non-elevated sessions (#40047)

* wslc Pretty-print JSON output for inspect and list commands (#40051)

* Fix race condition in ContainerLogs test case (#40052)

* Add support for build logs (#40054)

* CLI: Table Output updates (#14534)

* Use COM marshalling to exchange handles  (#40056)

* Prototype

* Save state

* Save state

* Save state

* Save state

* Save state

* Save state

* Remove zeroing

* Apply PR feedback

* Add test coverage

* Format

* Add test coverage for null handles

* wslc: ensure dns tunneling is disabled with virtioproxy networking mode (#40057)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Implement SDK inspect and VHD management (#14545)

Implements `WslcInspectContainer` and `WslcCreateSessionVhd`; adds `WslcSetContainerSettingsNamedVolumes` so that the VHDs are useful.

* CLI: Add Terminate Session command (#40058)

* List and inspect named volumes (#14555)

* CLI: Add table support to always show header, default true (#40061)

* Keep track of handle types in the service (#40062)

* Keep track of handle types in the service

* Only duplicate on return

* Format

* Switch DmesgOutput to a WSLCHandle (#40063)

* Add repository, tag, ID and created columns to image list output (#40043)

* Add port mappings to container list output (#14438)

* HostFileShareMode (#40068)

* Fix and improve interactive tests (#40069)

* Add a DllMain method to wslcsdk and configure tracelogging (#40070)

* Add a DllMain method to wslcsdk and configure tracelogging

* Explicitely initialize WIL

* Fix race condition in ElevatedTokenCanOpenNonElevatedHandles test case (#40071)

* Suppress MSI-initiated reboots during Store updates (#40074)

When the WSL MSIX package is updated via the Microsoft Store, the
WslInstaller service automatically upgrades the MSI package by calling
MsiInstallProduct. This call was made with INSTALLUILEVEL_NONE (silent
install) but without setting the REBOOT=ReallySuppress property.

Per Windows Installer documentation, when a silent install encounters
files in use and REBOOT is not suppressed, the system reboots
automatically without any user prompt. This could cause unexpected
machine restarts after a Store update when WSL binaries (e.g.
wslservice.exe) were in use during the upgrade.

Every deployment script in the repo already passes /norestart to
msiexec (deploy-to-host.ps1, deploy-to-vm.ps1, install-latest-wsl.ps1,
test-setup.ps1), but the programmatic MsiInstallProduct path used by
the WslInstaller service lacked the equivalent property.

This change:
- Always appends REBOOT=ReallySuppress to MsiInstallProduct arguments
  in UpgradeViaMsi, preventing Windows Installer from ever initiating
  a system restart during install/upgrade.
- Switches UninstallViaMsi from MsiConfigureProduct to
  MsiConfigureProductEx so we can pass REBOOT=ReallySuppress during
  uninstall as well.
- Propagates ERROR_SUCCESS_REBOOT_REQUIRED (3010) to callers instead
  of swallowing it. User-facing paths (wsl --update, wsl --uninstall)
  print a reboot-needed message to stderr. The background WslInstaller
  service silently treats 3010 as success since it has no console.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Don't fail to start a WSLCSession if anonymous volumes are present (#40077)

* Don't fail to start a WSLCSession if anonymous volumes are present

* Typo

* Cleanup diff

* Cleanup diff

* devicehost: stop re-signing and rely on MSIRMSHUTDOWN for file-in-use handling (#40080)

* devicehost: stop re-signing and fix MSI installer failing to replace
wsldevicehost.dll

* pr feedback

* use MSIRMSHUTDOWN = 1 instead of custom action

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Use THROW_HR_WITH_USER_ERROR for TTY console check (#40084)

Replace manual PrintMessage + THROW_HR(E_FAIL) with the standard
THROW_HR_WITH_USER_ERROR pattern used throughout the codebase. This
ensures the error message is properly captured by the ExecutionContext
error collection system rather than being printed directly to stderr.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Add week/month/year support to FormatRelativeTime (#40083)

* Add week/month/year support to FormatRelativeTime

Previously only handled seconds, minutes, hours, and days. Containers
older than a week would show e.g. '720 days ago' instead of '2 years ago'.

Now matches Docker-style output with weeks, months, and years.
Also refactors repeated pluralization logic into a lambda.

* Handle timestamp==0 sentinel in FormatRelativeTime

Callers pass 0 to mean 'unknown' (e.g. ImageTasks when Created <= 0).
Previously this would produce '56 years ago'. Now returns empty string.

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Remove dead code: SetContainerTTYOptions and SetContainerArguments (#40087)

Both static functions in ContainerService.cpp are defined but never
called from anywhere in the codebase. They appear to be remnants of
an earlier implementation before the WSLCContainerLauncher and
WSLCProcessLauncher classes took over this responsibility.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Fix callback parameter shadow in CreateInternal (#40086)

* Remove unused callback parameter from CreateInternal

The IProgressCallback* parameter was always passed as nullptr by both
callers. The auto-pull path creates its own PullImageCallback locally.
Remove the dead parameter entirely per review feedback.

* format

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Allow small timestamp difference in ContainerRecoveryFromStorage test (#40081)

* Allow small timestamp difference in ContainerRecoveryFromStorage test

* feedback

* Localization change from build: 143632468 (#40094)

Co-authored-by: WSL localization <noreply@microsoft.com>

* Release COM DLLs before installer test MSI operations (#40093)

* Release COM DLLs before installer test MSI operations

Add PrepareForMsiOperation() that calls CoFreeUnusedLibrariesEx(0)
before each msiexec invocation. This releases in-process COM DLLs
like wslserviceproxystub.dll loaded by prior test classes, preventing
the Restart Manager from detecting the test process as holding file
locks and failing the install on older Server SKUs like ni_release.

* fix CoFreeUnusedLibrariesEx

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Localize all user-facing wslc.exe CLI strings (#40089)

* Localize all user-facing wslc.exe CLI strings

Add localization entries for all hardcoded user-facing strings in the
WSLC CLI tool:

- 38 command description strings (Short + Long for all commands)
- 30 argument description strings in ArgumentDefinitions.h
- Settings reset confirmation string
- All entries added to en-US/Resources.resw with {Locked=...} comments
  for CLI flags, product names, and technical terms

E2E tests updated to use Localization:: calls and dynamic column
formatting instead of hardcoded string copies, so they won't go
stale when descriptions change.

* formatting

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Validate container path is absolute in VolumeMount::Parse (#40085)

* Validate container path is absolute in VolumeMount::Parse

Add validation that non-empty container paths must start with '/' since
they are Linux paths inside the container. This catches cases where
Windows drive letter colons (e.g. C:\path) get misinterpreted as the
host:container separator, producing invalid container paths like
'\hostPath' instead of '/containerPath'.

Previously, 'C:\hostPath:ro' would silently parse as host='C',
container='\hostPath', mode=ro ΓÇö now it throws a clear error.

Updated tests to reflect the new validation and moved previously
'valid' but semantically incorrect cases to the invalid test set.

* Also validate host path is absolute, add format hint to error, cover forward-slash cases

- Reject non-absolute host paths (catches C:/hostPath where host='C')
- Add 'Expected format:' hint to container path error message for consistency
- Add forward-slash drive letter cases to invalid test set
- Move '::' case to invalid (host=':' is not absolute)

* Remove host path is_absolute check to allow future named volumes

Per review feedback: named volumes (e.g. 'test_vol:/path') would fail
an is_absolute() check on the host path. Keep only the container path
validation (must start with '/') which doesn't conflict with named
volume identifiers.

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Localization change from build: 143644543 (#40098)

Co-authored-by: WSL localization <noreply@microsoft.com>

* Initialize user option support and added E2E tests (#40101)

* Init user option support

* Init e2e test

* Added more E2E Tests

* Fix test

* Clang format

* Fix test

* Rename test to UnknownGroup_Fails to reflect actual failure mode

Agent-Logs-Url: https://github.com/microsoft/WSL/sessions/0e095692-5673-4e8f-ad7f-47deccb74ec9

Co-authored-by: AmelBawa-msft <104940545+AmelBawa-msft@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* Add logic to clean up images created during the tests (#40078)

* Save state

* Format

* Log failures

* Format

* Add response size limit to Docker HTTP client (#40097)

SendRequestAndReadResponse accumulates the entire response body into
a std::string with no size limit. While all current callers expect
small JSON metadata responses, a pathological or malformed response
could cause unbounded memory growth.

Add a 64 MB limit to prevent OOM. This is generous for JSON metadata
(list/inspect/create responses are typically <1 MB) while still
catching runaway responses early.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* [WSLC] Add --workdir / -w option to 'wslc exec' (#40041)

* [WSLC] Add --workdir / -w option to 'wslc exec'

Adds a --workdir (-w) argument to the exec command that sets the working
directory inside the container for the executed process. Wires the value
through ContainerOptions into WSLAProcessLauncher::SetWorkingDirectory.

Co-authored-by: Pooja Trivedi <trivedipooja@microsoft.com>
Co-Authored-By: Claude Sonnet 4.6

* Update test/windows/wslc/CommandLineTestCases.h

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update test/windows/wslc/CommandLineTestCases.h

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix clang formatting issues

* Update test/windows/wslc/WSLCCLIExecutionUnitTests.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Add E2E tests for wslc container exec, including --workdir option

- Port existing exec E2E tests from feature branch
- Add WSLCE2E_Container_Exec_WorkDir and WSLCE2E_Container_Exec_WorkDir_ShortAlias tests
- Update help message in GetAvailableOptions to include -w,--workdir

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix clang formatting in WSLCE2EContainerExecTests.cpp

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Validate --workdir is non-empty; add unit and parse test cases

- Reject empty or whitespace-only --workdir in Argument::Validate
- Add ExecCommand_ParseWorkDirEmptyValue_ThrowsArgumentException unit test
- Add empty-workdir failing case to CommandLineTestCases.h

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix clang formatting in CommandLineTestCases.h

Co-Authored-By: Claude Sonnet 4.6

* Trim exec E2E tests to --workdir coverage only

Remove tests that duplicate existing coverage in WSLCE2EContainerCreateTests.cpp.
Keep only the help message test (validates --workdir appears in output) and the
two workdir-specific E2E tests.

Co-Authored-By: Claude Sonnet 4.6

* Missed change from merge conflict resolution

* Fix --workdir whitespace validation to use std::iswspace for full Unicode coverage

Agent-Logs-Url: https://github.com/microsoft/WSL/sessions/b21d1a57-bb3f-4a12-84cf-8e414a453890

Co-authored-by: ptrivedi <1638019+ptrivedi@users.noreply.github.com>

* Use lambda with wint_t cast in iswspace call to avoid potential UB

Agent-Logs-Url: https://github.com/microsoft/WSL/sessions/b21d1a57-bb3f-4a12-84cf-8e414a453890

Co-authored-by: ptrivedi <1638019+ptrivedi@users.noreply.github.com>

* Missed change from merge conflict resolution

* Address Copilot PR feedback

- Revert Version ArgType alias from NO_ALIAS back to L"v" to preserve existing -v short option
- Restore WSLCE2EContainerExecTests.cpp lost in merge conflict resolution

Co-Authored-By: Pooja Trivedi

* Update src/windows/wslc/services/ContainerService.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix ParserTest_StateMachine_PositionalForward: replace -v with -h in flag parse tests

The -v short alias was removed from --verbose (changed to NO_ALIAS) to
resolve a triple alias conflict with --version and --volume. The parser
test cases in the Run argument set still used -v expecting it to resolve
to --verbose, but since neither Version nor Volume are in the Run set,
-v became unresolvable and caused unexpected parse failures.

Replace -v with -h (help flag) in the flag parse test cases to preserve
the same combined-flag parsing coverage with a valid short alias.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix E2E exec help test: add --user option after base branch merge

After merging feature/wsl-for-apps, the --user argument is now active
in ContainerExecCommand (from PR #40101). Update the expected exec help
output to include -u,--user.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Pooja Trivedi <trivedipooja@microsoft.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ptrivedi <1638019+ptrivedi@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Implement wslc session enter (#40088)

* Save state

* Save state

* Save state

* Cleanup

* Prepare for PR

* Cleanup

* Validate flags

* Apply PR suggestions

* Add comment

* Remove include

* Cleanup diff

* Format

* Format

* Restore session flags

* Make VMPortMapping::Unmap idempotent (#40091)

* Make VMPortMapping::Unmap idempotent

Null out Vm after unmapping so a second call is a no-op. This prevents
double-unmap errors when ReleaseRuntimeResources is called from both
OnEvent(Stop) and a concurrent Delete(Force) path.

* Clear Vm before re-throwing on UnmapPort failure

Use a scope_exit to null Vm so that Unmap() is truly idempotent
even when UnmapPort() throws. Previously Vm stayed non-null on
the failure path, causing subsequent Unmap() calls to retry and
throw again.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Correctly handle empty arguments & entrypoint when launching containers (#40122)

* Correctly handle empty arguments & entrypoint when launching containers

* Apply PR feedback

* Add logic to reject invalid flags (#40100)

* Add logic to reject invalid flags

* Simplify tests

* Use macros

* Format

* Format

* wslc: implement dns tunneling for virtio proxy networking mode (#40104)

* wslc: implement dns tunneling for virtio proxy networking mode

This change implements dnstunneling for the virtio proxy networking mode. For now, this implementation uses the same socket-based approach, but in the fututure this will be moved over to the built-in dns support that is part of the wsldevicehost dll.

* wslc: enable DNS tunneling by default for virtio proxy

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove unused DNS test helpers

VerifyDnsResolutionDig and VerifyDnsResolutionRecordTypes are dead
code — VerifyDnsQueries is the superset that covers all record types
and TCP/UDP modes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* [WSLC] Add 'wslc version' subcommand (#14547)

* [WSLC] Add 'wslc version' subcommand

Adds a 'version' subcommand to the WSLC CLI as an alternative to the
existing '--version' flag, following the subcommand pattern used by
other WSLC commands. Includes unit tests for command structure and
command-line parsing.

Co-authored-by: Pooja Trivedi <trivedipooja@microsoft.com>
Co-Authored-By: Claude Sonnet 4.6

* [WSLC] Fix E2E help/invalid-command tests after version subcommand addition

Update expected help output in WSLCE2EGlobalTests to include the newly
added 'version' subcommand, fixing WSLCE2E_HelpCommand and
WSLCE2E_InvalidCommand_DisplaysErrorMessage test failures.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [WSLC] Add E2E version command test and strengthen unit test

- Add WSLCE2E_VersionCommand E2E test in WSLCE2EGlobalTests verifying
  stdout, empty stderr, and exit code for 'wslc version'
- Add assertion to VersionCommand_HasNoArguments unit test to verify
  only the auto-added --help argument is present

Authored-By: Pooja Trivedi <trivedipooja@microsoft.com>
Co-Authored-By: Claude Sonnet 4.6

* Mark 'context' as UNREFERENCED_PARAMETER in
VersionCommand::ExecuteInternal to avoid build issues

* Address PR feedback on wslc version command

- Use Localization::WSLCCLI_VersionDesc/LongDesc instead of hard-coded strings; add entries to en-US Resources.resw
- Centralize version printing in VersionCommand::PrintVersion(); reuse from RootCommand --version flag
- Drop 'v' prefix from version output per OneBlue's feedback
- Add 'version' entry to E2E GetAvailableCommands() to fix WSLCE2E_HelpCommand and WSLCE2E_InvalidCommand_DisplaysErrorMessage

Co-Authored-By: Pooja Trivedi

* Fix build: add missing using namespace wsl::shared

Localization::WSLCCLI_VersionDesc() and WSLCCLI_VersionLongDesc() live in
wsl::shared::Localization. Without this using directive the compiler cannot
resolve the unqualified Localization:: references in VersionCommand.cpp.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Pooja Trivedi <trivedipooja@microsoft.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add E2E test for --version flag (#40125)

* Add E2E test for --version flag

Ensures both entry points (the 'version' subcommand and the '--version' flag)
are covered by E2E tests, preventing the two paths from drifting.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix newline

---------

Co-authored-by: Pooja Trivedi <trivedipooja@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update WSLCCreateSession event to critical. (#40065)

* Updated event to critical

* Updated event

* Apply suggestion from @craigloewen-msft

* Revert "Apply suggestion from @craigloewen-msft"

This reverts commit 7800a3558725c71ef58cb5229e74e98d97fa16b3.

* [CLI] Initialize tmpfs support (#40128)

* Init tmpfs support

* Resolve copilot comment

* Fail the session creation if the virtionet interface can't be initialized (#40124)

* Fail the session creation if the virtionet interface can't be initialized

* Apply PR feedback

* Add DCOM LaunchPermission for WSLCSessionFactory (#40134)

* Add DCOM LaunchPermission for WSLCSessionFactory

WSLCSessionFactory (wslcsession.exe) was registered without an AppId or
explicit DCOM LaunchPermission. When wslservice (SYSTEM) impersonates a
non-interactive caller such as Network Service and calls
CreateComServerAsUser to launch the per-user session factory, DCOM falls
back to machine-default launch permissions which do not include service
accounts. This causes E_ACCESSDENIED during session creation.

Add an AppId with the same LaunchPermission and AccessPermission SDDL
used by the other WSL COM servers (LxssUserSession, WSLCSessionManager,
WslDeviceHost), granting launch/activate rights to Authenticated Users
(AU), Principal Self (PS), and Local System (SY).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Extract DCOM permission blob into CMake variable

The same binary security descriptor was duplicated 8 times across 4 AppId
registrations. Extract it into a DCOM_PERMISSION CMake variable defined in
msipackage/CMakeLists.txt so future permission changes only need one edit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix race condition when building multiple IDL files (#40130)

* Fix race condition when building multiple IDL files

* Use the header as output

* Use a single target

* Use a separate command to set the stamp file

* Remove stamp file

* CLI: Fix forwarded args beginning with '-' from being a parser error (#40131)

* Refactor tests: use TAEF metadata for WSL version filtering (#40129)

Replace runtime WSL2_TEST_ONLY()/WSL1_TEST_ONLY() skip macros with
TAEF metadata-based test selection. Tests that don't apply to the
current WSL version are now excluded by /select: queries at selection
time rather than skipped at runtime, eliminating hundreds of 'skipped'
results from test output.

Changes:
- Add WSL2_TEST_METHOD, WSL1_TEST_METHOD, WSLC_TEST_METHOD macros
  in Common.h that tag tests with WSLVersion metadata property
- Convert ~430 test methods across 26 files to use new macros
- Update run-tests.ps1 to auto-add /select: version filter
- Update CloudTest XML configs with version selection queries
- Remove WSL2_TEST_ONLY() from composite macros in NetworkTests.cpp
- Update test README with new macro documentation

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix tmpfs tests to use WSLC_TEST_METHOD macro (#40143)

Replace WSL2_TEST_ONLY() runtime skip macro (removed in #40129) with
WSLC_TEST_METHOD metadata macro in tmpfs tests added by #40128.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove cloudtest notifications sent to lowdev (#40046)

* Remove build notifications sent to lowdev

* Use GH email

* Use VSO email

* Log email

* Iterate

* Remove notification entirely

* CLI: Add initial support for image tag command (#14416)

* Initial support for image tag command

* Init test

* Init e2e test

* Adde E2E tests

* Added more tests

* Added more tests

* Resolve copilot comment

* Clang format

* Clang format

* Fix build

* Update parser

* Update loc

* Fix test

* Added more tests

* Clang format

* Loc

* Addressed comments

* Add support for mounting files and non-existing folders as volumes  (#40137)

* Save state

* Prepare for PR

* Apply PR feedback

* Add test coverage for restored containers

* Merge

* Reset m_dockerdProcess when terminating a session (#40146)

* Fix incorrect --detach description in container run help text (#40149)

The help text for 'wslc container run' incorrectly stated that
containers start in the background by default and --detach runs in
the foreground. The actual behavior (confirmed by ContainerService.cpp)
is the opposite: containers start attached (foreground) by default,
and --detach runs them in the background.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add preview disclaimer to WSLC SDK header and NuGet package (#40153)

Add preview notice to wslcsdk.h header comment block, NuGet README,
and nuspec description to clearly communicate that the WSLC SDK API
is subject to breaking changes during the preview period.

Also fix incorrect header filename reference in README (WSLCApi.h -> wslcsdk.h).

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix API review issues in wslcsdk.h and wslcsdk.cpp (#40150)

- Add missing SAL annotations to WslcGetContainerID (_In_, _Out_writes_)
- Fix typo: 'recieve' -> 'receive' in WslcStdIOCallback documentation
- Fix parameter naming: 'NameOrId' -> 'nameOrId' to match lowercase
  convention used by all other API parameters

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add wslcsession.exe to diagnostic log collection (#40151)

Include the WSLC session service process in the list of executables
that collect-wsl-logs.ps1 captures memory dumps for. This improves
diagnostics for container-related issues where the session service
state is relevant.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Initial prune image support in wslc service (#40132)

* Improve errors returned from WSLCContainer (#40147)

* Improve container state errors

* Add wslc.exe test coverage

* Fix localization file

* Apply PR suggestions

* Format

* Add negative test cases for WSLC SDK error paths (#40152)

Add 10 new WSLC SDK tests covering critical error handling gaps:
- Null handle release/terminate (session, container, process)
- Container creation with null session
- Stop container with invalid signal value
- Exec process on stopped container
- Duplicate container name rejection
- Delete running container without force flag
- Delete non-existent image
- Pull with invalid image name/registry URL

These tests verify that the SDK properly rejects invalid inputs
and returns appropriate error codes rather than crashing.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix SDK tests to use new WSLC_E_CONTAINER error codes (#40165)

* Enhance and organize test execution (#40108)

* container attach

* Enhance tests

* Move more tests to run

* Init exec

* Clang format

* Resolve copilot comment

* Replace S_OK with 0

* Added error messages

* Resolve copilot comment

* Clang format

* Fix tests

* Resolve copilot comment

* Fix incorrect regeneration for IDL targets (#40148)

* Add registry authentication in runtime (#40123)

* wslc: prevent session name squatting for default WSLc sessions (#40144)

* Prevent session name squatting for default WSLc sessions

- Server now determines default session name and settings from caller's
  token, preventing malicious users from squatting reserved session names
- CreateSession rejects explicit use of reserved names (wslc-cli,
  wslc-cli-admin) with case-insensitive E_ACCESSDENIED check
- Null StoragePath remains valid for ephemeral sessions; empty string
  is rejected as E_INVALIDARG
- Add dedicated EnterSession API with null/empty parameter validation
- Early return optimization: skip YAML parse if default session exists
- Inline BuildFeatureFlags into SessionSettings constructor
- Extract UserSettings into shared wslcsettings library used by both
  wslc.exe and wslservice.exe
- Move EnumVariantMap.h to common
- Fix std::terminate crash in CustomDmesgOutput test when CreateSession
  fails by adding a scope_exit guard to join the reader thread
- Add session name squatting E2E test with case-insensitive coverage

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR feedback: per-user session names, custom error codes, impersonation

- Append username to default session names so different users don't
  collide (e.g. wslc-cli-alice, wslc-cli-admin-bob) [OneBlue]
- Impersonate caller when loading settings.yaml server-side [OneBlue]
- Factor name resolution into ResolveDefaultSessionName helper [OneBlue]
- Add WSLC_E_SESSION_RESERVED and WSLC_E_INVALID_SESSION_NAME error
  codes for better diagnosability [dkbennett]
- Use prefix-based reserved name check (blocks all wslc-cli-* names)
- Fix pre-existing HostFileShareMode namespace qualification bug
- Remove unused variable in GetDefaultStoragePath test helper [Copilot]
- Update all E2E tests for username-qualified session names

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix port conflict error message and cleanup on failure (#40102)

* Don't return catch-all error messages for non-WSL specific error codes (#40163)

* Don't return catch-all error messages for non-WSL specific error codes

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update test error message expectations to match actual behavior

- ImportDistro: Remove 'Failed to create disk' wrapper since the error
  occurs before CreateVhd, producing only the raw system error message
- ModernDistroInstall: Update to raw Win32 message for ERROR_ALREADY_EXISTS
  since the mapping was removed from GetErrorString and InstallDistro
  path doesn't use THROW_HR_WITH_USER_ERROR

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update test messages

* Format

* Update localization/strings/en-US/Resources.resw

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply new string name

* Use the right error message for wsl1

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Richfr/ Add windowsAddress support to WslcCreateContainer() API (#40037)

* Portmapping: add windowsAddress support

* Portmapping: add windowsAddress support

* Addressing PR feedback: update wslcsdk.cpp

* Addressing clang formatting error

* Providing default values for port bindings: wslcsdk.cpp

* Added new function InetNtopToHresult() to map inet result error values to the correct HRESULTS

* return family name if socket address is invalid

* Removed unnecessasry variable bindingAddressStrings. Also, commented that convertedPorts must stay in same scope as containerOptions and moved the declaration to be with that var

* Fixed clang formatting errors

* Added WSLC Sdk API tests for WslcContainerPortMapping.windowsAddress for Ipv4 and Ipv6 local host.

* Add unique name to containerSettings var to make test debugging from log reports easier.

* Adjust AF_UNIX portmapping test so that it fails if value accepted

* Return more accurate strncpy_s error result

* Improved error return value of IP address verification

* Provide better error reporting

* Respond to misc copilot feedback

* Resolving merge after syncing with origin

* Adjusted error messages

* Removed 2 unnecessary lines of code

* Mark internal function as static to avoid external linkage

---------

Co-authored-by: Richard Fricks <richfr@microsoft.com>

* Add support for --no-cache in BuildImage() & wslc.exe (#40174)

* Add support for --no-cache in BuildImage() & wslc

* Update test/windows/WSLCTests.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Add try / CATCH_LOG() to the child logic when handling a WSLC_FORK message (#40180)

* Add try / CATCH_LOG() to the child logic when handling a WSLC_FORK message

* Propagate exceptions on failure

* wslc: add --workdir/-w support to container create and run (#40190)

Extends the --workdir flag (already supported by container exec) to
the container create and run commands, passing the working directory
through to the container launcher. Adds CLI parse tests, unit tests,
and E2E tests for both commands.

Co-Authored-By: Claude Sonnet

Co-authored-by: Pooja Trivedi <trivedipooja@microsoft.com>

* Fix test cleanup by deleting a file left behind (#40191)

* Update volume APIs to match docker arguments (#40181)

* Always show container logs during image builds (#40186)

* Add logic to keep track of COM callbacks and cancel them if the sessi… (#40183)

* Add logic to keep track of COM callbacks and cancel them if the session is terminating

* Apply PR feedback

* Format

* Reset the test session

* Apply PR feedback

* Apply PR suggestions

* CLI: Relative volume path support, improved error detection and messaging, more volume tests (#40193)

* Bump Microsoft.NETCore.App.Runtime to 10.0.6 (CVE-2026-32178) (#40203)

Update Microsoft.NETCore.App.Runtime.win-x64 and
Microsoft.NETCore.App.Runtime.win-arm64 from 10.0.4 to 10.0.6 to
resolve CVE-2026-32178 (.NET Spoofing Vulnerability).

Fixes Dependabot alerts #12 and #13.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Change image size to match docker image size calculation (#40210)

* Add `wslc login`, `wslc logout`, and `wslc push` commands for registry authentication (#40173)

* Remove unused Elevated parameter from SessionSettings::Default (#40205)

The Elevated parameter was passed to SessionSettings::Default() but
never referenced in the function body. The elevation state is already
encoded in the resolved session name (via ResolveDefaultSessionName
which uses DefaultAdminSessionName for elevated tokens), making this
parameter redundant dead code.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add missing trailing newlines to source files (#40202)

Several files were missing the POSIX-required trailing newline,
causing 'No newline at end of file' warnings from git and some
compilers. Files fixed:
- WSLCVhdVolume.cpp
- WSLCVhdVolume.h
- WSLCVolumeMetadata.h
- ImageTagCommand.cpp
- wslutil.cpp
- CMakeLists.txt (service/exe)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix empty string UB in ParseSizeBytes and missing null check in PruneContainers (#40204)

Two bugs found during deep review:

1. WSLCVhdVolume.cpp ParseSizeBytes: accessing value[0] without
   checking if the string is empty causes undefined behavior. An
   empty SizeBytes driver option would trigger a read past the end
   of the string. Add value.empty() guard before the sign check.

2. WSLCSession.cpp PruneContainers: the Result output parameter is
   dereferenced without null validation, unlike the analogous
   PruneImages method which correctly checks all output pointers.
   Add RETURN_HR_IF_NULL and ZeroMemory initialization to match
   the established pattern.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* wslc: remove redundant short-alias E2E tests for --workdir (#40192)

* wslc: add --workdir/-w support to container create and run

Extends the --workdir flag (already supported by container exec) to
the container create and run commands, passing the working directory
through to the container launcher. Adds CLI parse tests, unit tests,
and E2E tests for both commands.

Co-Authored-By: Claude Sonnet

* wslc: remove redundant short-alias E2E tests for --workdir

Short-alias (-w) coverage is already provided by the help message
test method and CLI parse tests. Remove the duplicate E2E tests
for container create and run per reviewer feedback.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Pooja Trivedi <trivedipooja@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add test coverage for LoadImage/ImportImage on process exit/session terminate (#40172)

* Add test covergae for LoadImage/ImportImage on process exit/session terminate

* fix handle read interupt

* do not leak container

* Add --pull and --target flags to image build (#40216)

* Fix wslc port relay buffer size to match non-WSLC relay path (#40217)

* CLI: Make image save output optional (#40194)

* Image save optional output

* Clang format

* Update test/windows/wslc/e2e/WSLCE2EImageSaveTests.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix terminal detection in CI for WSLCE2E_Image_Save_ToTerminal_Fail test

- Open CONOUT$ as child stdout in RunWslcAndRedirectToFile when no output
  path is given, so IsConsoleHandle() returns true in the child process
  regardless of how CI redirects the test runner's stdout
- Fix SavedArchivePath.wstring() -> SavedArchivePath in WSLCE2E_Image_Save_ToStdout_Load
- Quote output path in effectiveCommandLine for diagnostic clarity

Agent-Logs-Url: https://github.com/microsoft/WSL/sessions/f94556e1-9acd-40f1-89bd-349e238e92f3

Co-authored-by: AmelBawa-msft <104940545+AmelBawa-msft@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* wslc: add network create, delete, and list (#40179)

* Change help flag (#40236)

* Fix bugs found during code review of feature/wsl-for-apps (#40248)

- Fix wrong variable in waitpid check (init.cpp): Used 'Result' (poll return
  value) instead of 'Pid' (waitpid return value), causing incorrect SIGCHLD
  handling that could miss child exits or fail to detect init termination.

- Fix missing semicolon after LOG_ERROR (WSLCInit.cpp): Missing statement
  terminator would cause compilation failure on Linux builds.

- Fix misleading test comment (WSLCTests.cpp): Comment referenced port 1234
  but the test actually validates port 1236 cleanup after bind failure.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* CLI: TableOutput unit tests (#40095)

* Initial prune image cli command (#40239)

* Use WSLC_E_CONTAINER_NOT_FOUND when a container is not found (#40251)

* Use WSLC_E_CONTAINER_NOT_FOUND when a container is not found

* Format

* Add DeleteVolumes flag to container deletion API (#40232)

* Start containerd before dockerd (#40237)

Instead of letting dockerd manage its own embedded containerd, this starts containerd as a separate process first and points dockerd at its socket (--containerd /run/containerd/containerd.sock). My testing shows ~1s improvement with this.

* cp

* clang

* clang

* clang3

* event name

---------

Co-authored-by: Darshak Bhatti <dabhatti@micorsoft.com>

* Merge latest master into feature/wsl-for-apps (#40254)

* test: enable virtiofs tests and enable WSLG during testing (#14387)

* test: enable virtiofs tests and enable WSLG during testing

* test fix

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* chore(distributions): Almalinux auto-update - 20260311 14:52:02 (#14404)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Fix CVE-2026-26127: bump .NET runtime from 10.0.0 to 10.0.4 (#14421)

Addresses Dependabot alerts #10 and #11. The Microsoft.NETCore.App.Runtime
packages (win-x64 and win-arm64) at version 10.0.0 are vulnerable to a
denial of service via out-of-bounds read when decoding malformed Base64Url
input (CVSS 7.5 High). Bumped to 10.0.4 which includes the fix.

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Notice change from build: 141806547 (#14423)

Co-authored-by: WSL notice <noreply@microsoft.com>

* Ship initrd.img in MSI using build-time generation via powershell script (#14424)

* Ship initrd.img in MSI using build-time generation via tar.exe

Replace the install-time CreateInitrd/RemoveInitrd custom actions with a
build-time step that generates initrd.img using the Windows built-in
tar.exe (libarchive/bsdtar) and ships it directly in the MSI.

The install-time approach had a race condition: wsl.exe could launch
before the CreateInitrd custom action completed, causing
ERROR_FILE_NOT_FOUND for initrd.img.

Changes:
- Add CMake custom command to generate initrd.img via tar.exe --format=newc
- Add initrd.img as a regular file in the MSI tools component
- Remove CreateInitrd/RemoveInitrd custom actions from WiX, DllMain,
  and wslinstall.def
- Remove CreateCpioInitrd helper and its tests (no longer needed)
- Update pipeline build targets to build initramfs instead of init

* pr feedback

* more pr feedback

* switch to using a powershell script instead of tar.exe

* powershell script feedback

* hopefully final pr feedback

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* virtiofs: update logic so querying virtiofs mount source does not require a call to the service (#14380)

* virtiofs: update logic so querying virtiofs mount source does not require a call to the service

* more pr feedback

* use std::filesystem::read_symlink

* pr feedback and use canonical path in virtiofs symlink

* make sure canonical path is always used

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* virtio networking: add support for ipv6 (#14350)

* VirtioProxy: Add IPv6 address, gateway, and route support

- Add PreferredIpv6Address field and GetBestGatewayV6* methods to NetworkSettings
- Extend GetHostEndpointSettings() to discover IPv6 unicast address and gateway
- Add UpdateIpv6Address() using ModifyGuestEndpointSettingRequest<IPAddress>
- Push IPv6 default route to guest via UpdateDefaultRoute(AF_INET6)
- Remove AF_INET6 early return in ModifyOpenPorts, use INETADDR_PORT()
- Add EndpointRoute::DefaultRoute() static factory
- Pass client_ip_ipv6 in devicehost options (not yet parsed by devicehost)
- Remove gateway_ip from devicehost options (only needed for DHCP)
- Include IPv6 DNS servers in non-tunneling DNS settings
- Add ConfigurationV6 and DnsResolutionAAAA tests

* cleanup and add more ipv6 tests

* added test coverage and minor updates

* clang format

* pr feedback

* format source

* pr feedback

* test fixes

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Track `bind` syscall when port is 0 (#14333)

* Initial work

* .

* pr feedback and add unit test

* minor tweaks an fix use after free in logging statement

* implement PR feedback

* hopefully final pr feedback

* pr feedback in test function

* Address PR feedback: add try/catch to TrackPort and PortZeroBind queue push

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Add iptables to list of apps to install in WSL (#14459)

There were instructions already on how to install tcpdump in WSL, but
iptables are also needed for the log collection to be complete, so this
PR adds instructions on how to also install iptables.

Co-authored-by: Andre Muezerie <andremue@linux.microsoft.com>

* Update Microsoft.WSL.DeviceHost to version 1.1.39-0 (#14460)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Moves all Ubuntu distros to the tar-based format (#14463)

* Move all supported Ubuntu images to the new format

We backported the build pipeline so all current LTSes come out in the new tar-based format

* Remove the appx based distros

All WSL users can run tar-based distros by now, right?
There is no benefit in maintaining both formats.

* Enable DNS tunneling for VirtioProxy networking mode (#14461)

- Allow VirtioProxy to keep EnableDnsTunneling=true in config, but clear
  socket-specific options (BestEffortDnsParsing, DnsTunnelingIpAddress)
- Suppress dedicated DNS tunneling hvsocket for VirtioProxy; tunneling
  is handled through the VirtioNetworking device host instead
- Set DnsTunneling flag on VirtioNetworkingFlags so the device host
  knows to tunnel DNS
- Expand SWIOTLB kernel cmdline to cover VirtioFs and VirtioProxy
- Bump DeviceHost package to 1.1.39-0
- Add VirtioProxy DNS test coverage for tunneling on/off
- Skip GuestPortIsReleasedV6 on Windows 10

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* test: disable LoopbackExplicit due to OS build 29555 regression (#14477)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Refactor: trim unnecessary DLL deps from COMMON_LINK_LIBRARIES (#14426)

* Refactor: trim unnecessary DLL deps from COMMON_LINK_LIBRARIES

- Split MSI/Wintrust install functions from wslutil.cpp into install.cpp
- Remove MI.lib, wsldeps.lib, msi.lib, Wintrust.lib, computecore.lib,
  computenetwork.lib, Iphlpapi.lib from COMMON_LINK_LIBRARIES
- Add per-target MSI_LINK_LIBRARIES, HCS_LINK_LIBRARIES, SERVICE_LINK_LIBRARIES
- Delay-load msi.dll and WINTRUST.dll for wsl.exe and wslg.exe
- Result: wslhost, wslrelay, wslcsdk, testplugin lose msi/wintrust startup imports;
  wsl.exe and wslg.exe defer msi/wintrust loading until actually needed;
  wslservice is the only target that imports computecore/computenetwork/Iphlpapi

* minor fixes to install.cpp that were caught during PR

* move to wsl::windows::co…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants